#include <stdio.h>
#include <stdlib.h>
#include "CAudioIC.h"
#include <elasys_server.h>


#define _MAX_PATH     260

ELAPI _CProfile_GetInt32(
    /* [in] */ AString appName,
    /* [in] */ AString keyName,
    /* [out] */ Int32 *pValue);

ELAPI _CProfile_GetAString(
    /* [in] */ AString appName,
    /* [in] */ AString keyName,
    /* [out] */ AStringBuf *pReturnedString);

EXTERN_C int CDECL _sprintf(char *buf, const char *fmt,...);

ECode CFileReader::FindRootName(wchar_t *pRootDirName)
{
    ECode ec = E_INVALID_ARGUMENT;
    Int32 ulDiskNum;
    int i = 0;
    char szDisk[10];
    AStringBuf_<32> asDiskType;
    AStringBuf_<_MAX_PATH> asServiceName;
    char DiskTypeName[20];

    ec = _CProfile_GetInt32("Info", "DiskNum", &ulDiskNum);
    if (FAILED(ec)) {
        kprintf("Can't find '[Info] DiskNum=' in elastos.cfg.\n");
        return ec;
    }

    strcpy(DiskTypeName, "FlashDisk");

    for (i = ulDiskNum; i > 0; i--) {
        _sprintf((char *)szDisk, "Disk%d",  i);
        kprintf("FindRootName disk name :%s.\n", szDisk);
        ec = _CProfile_GetAString(szDisk, "DiskType", &asDiskType);
        if (FAILED(ec)) {
            kprintf("ERROR: Can't find '[Disk%d] in elastos.cfg.\n", i);
            return ec;
        }

        if(0 == strcmp(DiskTypeName, asDiskType)){
            ec = _CProfile_GetAString(szDisk, "ServiceName", &asServiceName);
            if (FAILED(ec)) {
                kprintf("ERROR: Can't find '[Disk%d] ServiceName=' in elastos.cfg.\n", i);
                return ec;
            }
            kprintf("FindRootName ServiceName :%s.\n", (char *)asServiceName);
            _strtowcs(pRootDirName, asServiceName);
            return NOERROR;
        }
    }

    return ec;
}

ECode CFileReader::InitRoot(wchar_t *pRootDirName)
{
    IBasicFileSystem *pIBsFileSystem = NULL;
    IBasicDirectory *pIBsDirectory = NULL;
    ECode ec = NOERROR;

    ec = DzFindService(pRootDirName, (PInterface *)&pIBsFileSystem);
    if (FAILED(ec)) {
        kprintf("Failed InitRoot DzFindService ec:0x%x\n", ec);
        return ec;
    }

    // GetRoot
    ec = pIBsFileSystem->GetRoot(&pIBsDirectory);
    if (FAILED(ec)) {
        kprintf("Failed InitRoot GetRoot! ec:0x%x\n", ec);
        pIBsFileSystem->Release();
        return ec;
    }

    m_pI_FLASH_FileSystem = pIBsFileSystem;
    m_pI_FLASH_Directory = pIBsDirectory;

    return ec;
}

ECode CFileReader::Init()
{
    wchar_t wszRootDirName[20];
    ECode ec;

    //TODO m_pI_FLASH_FileSystem m_pI_FLASH_Directory!=NULL
    if((NULL != m_pI_FLASH_Directory)&&(NULL != m_pI_FLASH_FileSystem)){
        kprintf("FAILED CFileReader Init.\n");
        return NOERROR;
    }

    ec = FindRootName(wszRootDirName);
    if(FAILED(ec)){
        return ec;
    }
    kprintf("Init Get wszRootDirName:%S.\n", wszRootDirName);
    ec = InitRoot(wszRootDirName);
    if(FAILED(ec)){
        return ec;
    }
    m_pIBsFile = NULL;
    return NOERROR;
}

void CFileReader::DeInit()
{
    if(NULL != m_pI_FLASH_Directory){
        m_pI_FLASH_Directory->Release();
        m_pI_FLASH_Directory = NULL;
    }

    if(NULL != m_pI_FLASH_FileSystem){
        m_pI_FLASH_FileSystem->Release();
        m_pI_FLASH_FileSystem = NULL;
    }

    if(NULL != m_pIBsFile){
        m_pIBsFile->Sync();
        m_pIBsFile->Release();
        m_pIBsFile = NULL;
    }

    m_iFileSize = 0;
    m_uLastOffset = 0;
}

//wszInFullPathFileName without root dir. ex: d:\c.txt => c.txt
ECode CFileReader::OpenToRead(wchar_t* wszInFullPathFileName)
{
    ECode ec = NOERROR;
    IAbsoluteIO *iAb = NULL;

    kprintf("OpenToRead filename:%S.\n", wszInFullPathFileName);

    ec = m_pI_FLASH_Directory->CreateFile(wszInFullPathFileName,
            FileAccessMode_Read,
            FALSE,
            &m_pIBsFile);
    if (FAILED(ec)) {
        kprintf("FAILED CFileReader Open CreateFile! ec = 0x%x, wszInFullPathFileName:%S.\n",
        ec, wszInFullPathFileName);
        return ec;
    }

    iAb = IAbsoluteIO::Probe(m_pIBsFile);
    if (NULL == iAb) {
        kprintf("FAILED CFileReader OpenToRead Probe!\n");
        return E_ACCESS_DENIED;
    }
    ec = iAb->GetSize((Int32 *)&m_iFileSize);
    if (FAILED(ec)) {
        kprintf("FAILED CFileReader OpenToRead GetSize! ec = 0x%08x\n", ec);
        return ec;
    }
    kprintf("OpenToRead m_iFileSize:%d.\n", m_iFileSize);
    m_uLastOffset = 0;

    return ec;
}

//wszInFullPathFileName without root dir. ex: d:\c.txt => c.txt
ECode CFileReader::OpenToWrite(wchar_t* wszInFullPathFileName)
{
    ECode ec = NOERROR;

    ec = m_pI_FLASH_Directory->CreateFile(wszInFullPathFileName,
            FileAccessMode_ReadWrite,
            FALSE,
            &m_pIBsFile);
    if (FAILED(ec)) {
        kprintf("FAILED CFileReader OpenToWrite CreateFile! ec = 0x%x, wszInFullPathFileName:%S.\n",
        ec, wszInFullPathFileName);
        return ec;
    }

    m_iFileSize = 0;
    m_uLastOffset = 0;

    return ec;
}

void CFileReader::Close()
{
    if(NULL != m_pIBsFile){
        m_pIBsFile->Sync();
        m_pIBsFile->Release();
        m_pIBsFile = NULL;
    }
    m_iFileSize = 0;
    m_uLastOffset = 0;
}

void CFileReader::SetFileOffset(Uint32 UFileOffset)
{
    m_uLastOffset = UFileOffset;
}

int CFileReader::GetFileOffset()
{
    return (int)m_uLastOffset;
}

ECode CFileReader::ReadFile(Byte *ReadBuffer, int ReadSize, int* pReadedSize)
{
    ECode ec;
    IAbsoluteIO *iAb = NULL;
    int readedSize;
    MemoryBuf pmbbuf (ReadBuffer, ReadSize, 0);

    if (NULL == m_pIBsFile) {
        kprintf("Error!! m_pIBsFile is NULL!! %s, %d\n", __FILE__, __LINE__);
        return E_NO_CLASS_INFO;
    }

    //TODO:Can be optimized
    iAb = IAbsoluteIO::Probe(m_pIBsFile);
    if (NULL == iAb) {
        kprintf("FAILED CFileReader ReadFile Probe!\n");
        ec = E_ACCESS_DENIED;
        return ec;
    }
//    kprintf("m_uLastOffset:0x%x, ReadSize:0x%x,  ReadBuffer:0x%x.\n",
//        m_uLastOffset, ReadSize, ReadBuffer);
    ec = iAb->Read(m_uLastOffset, (Int32)ReadSize, &pmbbuf);
    if (FAILED(ec)) {
        kprintf("FAILED CFileReader CFileReader Read! ec = 0x%08x\n", ec);
        return ec;
    }
    readedSize = pmbbuf.GetUsed();
    m_uLastOffset += readedSize;
    if(NULL != pReadedSize)*pReadedSize = readedSize;
    return ec;
}

ECode CFileReader::WriteFile(Byte *WriteBuffer, int WriteSize, int* pWritedSize)
{

    ECode ec;
    IAbsoluteIO *iAb = NULL;
    int writedSize;

    MemoryBuf *pmbbuf = MemoryBuf::Alloc((Byte *)WriteBuffer, (Int32)WriteSize);
    if(NULL == pmbbuf){
        kprintf("CFileReader WriteFile not enough memory.\n");
        return E_OUT_OF_MEMORY;
    }

    if (NULL == m_pIBsFile) {
        kprintf("Error!! m_pIBsFile is NULL!! %s, %d\n", __FILE__, __LINE__);
        return E_NO_CLASS_INFO;
    }

    //TODO:Can be optimized
    iAb = IAbsoluteIO::Probe(m_pIBsFile);
    if (NULL == iAb) {
        kprintf("FAILED CFileReader WriteFile Probe!\n");
        return E_ACCESS_DENIED;
    }

    ec = iAb->Write(m_uLastOffset, *pmbbuf, (Int32*)&writedSize);
    if (FAILED(ec)) {
        kprintf("FAILED CFileReader WriteFile Write! ec = 0x%08x\n", ec);
        return ec;
    }

    m_uLastOffset += writedSize;
    m_iFileSize += writedSize;
    if(NULL != pWritedSize)*pWritedSize = writedSize;
    MemoryBuf::Free(pmbbuf);

    return ec;
}
